package main

import (
	"errors"
	"fmt"
	"net/http"
	"os"

	"protection/tool"
	"strings"
	"time"

	// mysqla "protection/mysqlA"
	myrpc "github.com/2217263633/kakarpc"

	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"github.com/go-co-op/gocron"
	"github.com/wonderivan/logger"
	"gopkg.in/yaml.v2"
)

// 声明服务端
func readConfig() {
	// logger.Info("读取配置文件")
	config_path := "./config"
	files, err := os.ReadDir(config_path)
	if err != nil {
		logger.Error("error reading config directory", err.Error())
		return
	}

	var rpcNames []string
	for rpcName := range myrpc.RpcClient {
		_rpcName := strings.Split(rpcName, ".")
		// logger.Info("rpcName:", _rpcName[0]+".yaml", rpcNames)
		if !tool.Include(rpcNames, _rpcName[0]+".yaml") {
			if time.Since(myrpc.RpcClient[rpcName].Heart) > time.Second*30 {
				logger.Info("rpcName:", rpcName, "掉线超过30秒")
				// 先不删除 不然会影响 gin 转发
				// delete(glo.RpcClient, rpcName)
				continue
			}
			rpcNames = append(rpcNames, _rpcName[0]+".yaml")
		}
	}

	for _, file := range files {
		conf := new(myrpc.YamlStruct)
		yamlFile, err := os.ReadFile(config_path + "/" + file.Name())
		if err != nil {
			logger.Error("error reading config file", err.Error())
			break
		}
		err = yaml.Unmarshal(yamlFile, conf)
		if err != nil {
			logger.Error("error unmarshalling config file", err.Error())
			return
		}
		// logger.Info("---rpcNames", rpcNames, file.Name())
		if !tool.Include(rpcNames, file.Name()) {
			logger.Info("file", file.Name(), "没有运行，已掉线", "路径:", rpcNames, conf.Server.Path)
		}
		myrpc.RpcServer[conf.Server.Chinese_name] = conf
	}
}

type LoginStruct struct {
	ID       int
	Username string
	Source   string
	jwt.StandardClaims
}

func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method
		origin := c.Request.Header.Get("Origin")

		if origin != "" {
			c.Header("Access-Control-Allow-Origin", c.GetHeader("origin")) // 可将将 * 替换为指定的域名
			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
			c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization,Self-TargetIP")
			c.Header("Access-Control-Allow-Credentials", "true")
		}
		if method == "OPTIONS" {
			c.AbortWithStatus(http.StatusNoContent)
			return
		}
		c.Next()
	}

}

func parseSign(secret string, tokenString string) (*LoginStruct, error) {
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (i interface{}, err error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return []byte(secret), nil
	})

	//err不为空，说明token已过期
	if err != nil {
		return nil, err
	}

	//将获取的token中的Claims强转为MapClaims
	claims, ok := token.Claims.(jwt.MapClaims)
	//判断token是否有效
	if !(ok && token.Valid) {
		return nil, errors.New("cannot convert claim to mapClaim")
	}

	info := &LoginStruct{
		ID:       int(claims["id"].(float64)),
		Username: claims["username"].(string),
	}

	if claims["source"] != nil {
		info.Source = claims["source"].(string)
	}
	return info, nil
}

func ParseToken(token string) (*LoginStruct, error) {
	login, err := parseSign("44872", token)
	return login, err
}

var jumpUrl []string = []string{
	"/api/v1/login",
	"/api/v1/code",
	"/api/v1/register",
	"/api/v1/msg/item",
	"/api/v1/person/single",
	"/api/v1/app/version",
	"swagger",
	"/api/v1/livekit",
}

func VerifyUser() gin.HandlerFunc {
	return func(c *gin.Context) {
		url := c.Request.URL
		for _, v := range jumpUrl {
			has := strings.Contains(url.Path, v)
			if has {
				c.Next()
				return
			}
		}

		tokens := ""
		if strings.Contains(url.Path, "/api/v1/ws") {
			tokens = c.GetHeader("Sec-WebSocket-Protocol")
		} else {
			tokens = c.GetHeader("Authorization")
		}
		loginStruct_, err := ParseToken(tokens)
		if err != nil {
			c.JSON(402, gin.H{"data": "token解析失败"})
			c.AbortWithStatus(http.StatusUnauthorized)
			return
		}

		c.Set("id", loginStruct_.ID)
		c.Next()
	}
}

func main() {
	judge()
	var rpc = myrpc.RPC{}
	gin.SetMode(gin.ReleaseMode)
	rpc.R = gin.Default()
	rpc.R.Use(Cors())

	myrpc.MyRpc.CenterInit(&rpc)
}

// 判断微服务是否连接正常
func judge() {
	ti := gocron.NewScheduler(time.UTC)
	logger.Info("开始定时任务,判断下发任务是否正常运行")
	ti.Every(10).Seconds().Do(readConfig)
	ti.StartAsync()
}
